'use strict'

const http=require('http')
const fs=require('fs')
const { resolve } = require('path/posix')
const fsp=fs.promises
/*
.jpg .jepg ->image/jpeg

.png ->image/png

.gif->image/gif

.ico ->image/x-icon

.txt->text/plain

.json->text/json或application/json

.xml->text/xml 或application/xml

*/ 
/**----------------------解析body数据----------------------- */
/** 
 * Content-Disposition:form-data;name="file",filename="xxx"
 * Content-Type:text/plain
@param {string}headerData
*/
function parseBodyHeaders(headerData){
    let hlist=headerData.split('\r\n').filter(p=>p.length>0)
    //解析content-disposition=>hlist[0]
    //按照;划分数组，选出从第二个元素开始的数组
    let csplit=hlist[0].split(';').slice(1)

    let filename
    let name
    
    for(let a of csplit){
        if(a.indexOf('filename=')===0){
            filename=a.substring(a.indexOf('=')+2,a.length-1)
        }else{
            name=a.substring(a.indexOf('=')+2,a.length-1)

        }

    }
    let headers={}
    let ind=0
    let k
    for(let h of hlist){
        ind=h.indexOf(':')
        k=h.substring(0,ind).toLowerCase()
        headers[k]=h.substring(ind+1).trim()
    }
    return{
        filename,
        name,
        headers,
        contentType:headers['content-type']||''
    }
}
function parseBody(bodyData,headers){
    let ctype=headers['content-type']
    let bdy=ctype.substring(ctype.indexOf('=')+1)
    let crlf_bdy=`\r\n--${bdy}`
    let header_end_index=bodyData.indexOf('\r\n\r\n',crlf_bdy.length)
    let headerData=bodyData.toString('utf8',crlf_bdy.length,header_end_index)

//解析文件头信息
    let hd=parseBodyHeaders(headerData)
    let file={
        start:header_end_index+4,
        end:bodyData.indexOf(crlf_bdy,header_end_index),
        ...hd
    }
    file.length=file.end-file.start
    return file
}
//解析文件扩展名
function parseExtName(filename){
    if(filename.length<2){
        return ''
    }
    let nsplit=filename.split('.').filter(p=>p.length>0)
    if(nsplit.length<2)return ''
    return `.${nsplit[nsplit.length-1]}`
}
/**----------------------解析body数据-END--------------------- */
let html=`
<!DOCTYPE html>
<html>
<head>
    <title>First HTTP</title>
</head>
<body>
    你好
</body>
</html>
`
let routerTable={
    GET:{
        '/':async(ctx)=>{
            response.setHeader('content-type','text/html; charset=utf-8')
            ctx.end(html)
        },
        '/test':async(ctx)=>{
            let status=parseInt(Math.random()*200)+199
            ctx.response.statusCode=status
            ctx.response.end('test end')
        },
        '/upload':async(ctx)=>{
            let stm=fs.createReadStream('./upload.html')
            stm.pipe(ctx.response,{end:false})
            stm.on('end',()=>{
                ctx.end()
            })
        },

    },
    POST:{
        '/data':async(ctx)=>{
            let fie=parseBody(ctx.rawBody,ctx.headers)
            console.log(file)
            if(!ctx.rawBody){
                ctx.end();
                return;
            }
            
            let fname=`${Data.now()}-${Math.random()}`+`${parseExtName(file.filename)}`;
            let fh=await fsp.open(fname,'w+')
            let fert=await fh.write(ctx.rawBody,
                                    file.start,file.length,0);
            // ctx.end(ctx.rawBody)
            //关闭打开的文件
            fh.close();
            ctx.end(`${fret.bytesWritten}`)
        }
    }
}
http.createServer(async(request,response)=>{
    let rm=routerTable[request.method]

    let usplit=request.url.split('?')
    let pathname=usplit[0]
    let querystring=usplit[1]||''
    if(!rm||!rm[pathname]){
        response.statusCode=404
        response.end('page not found')
        return
    }
    //ctx是context的缩写，意为请求上下文，就是一个打包了各种数据和方法的对象
    let ctx={
        method:request.method,
        path:pathname,
        search:querystring,
        headers:request.headers,
        response:response,
        end:(data,encoding='utf8')=>{
            response.end(data,encoding)
        },
        write:(data,encoding='utf8')=>{
            response.write(data,encoding)
        },
        totallength:0,
        rawBody:null,
        bufferList:[]
    }
    await new Promise((rv,rj)=>{
        if('PD'.indexOf(request.method[0])>=0){
            request.on('data',chunk=>{
                ctx.bufferList.push(chunk)
                ctx.totalLength+=chunk.length

            })
        }else{
            request.on('data',data=>{
                response.statusCode=400
                response.end('bad request',()=>{
                    request.destroy()
                })
            })
        }
        let resolved=false
        request.on('end',()=>{
            resolved=true
            rv();
        })
        request.on('close',()=>{
            (!resolved)&&rv();
        })
    })
    if(!response.writable||response.writableEnded){
        return
    }
    if(ctx.bufferList.length>0){
        ctx.rawBody=Buffer.concat(ctx.bufferList,ctx.totalLength)
        ctx.bufferList=[]
    }
    rm[pathname ](ctx)
})
.listen(3456)